package com.xxl.job.admin.service.impl;

import cn.hutool.core.util.StrUtil;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.model.XxlJobUser;
import com.xxl.job.admin.core.util.CookieUtil;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.core.util.JacksonUtil;
import com.xxl.job.admin.core.util.JwtAccessTokenGenerator;
import com.xxl.job.admin.dao.XxlJobUserDao;
import com.xxl.job.core.biz.model.ReturnT;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.math.BigInteger;
import java.util.Map;
import java.util.Objects;

/**
 * @author xuxueli 2019-05-04 22:13:264
 */
@Service
@Slf4j
public class LoginService {

    public static final String LOGIN_IDENTITY_KEY = "XXL_JOB_LOGIN_IDENTITY";
    public static final String LOGIN_IDENTITY_TOKEN = "token";

    @Resource
    private XxlJobUserDao xxlJobUserDao;

    @Resource
    private XxlJobAdminConfig xxlJobAdminConfig;


    // ---------------------- token tool ----------------------

    private String makeToken(XxlJobUser xxlJobUser) {
        String tokenJson = JacksonUtil.writeValueAsString(xxlJobUser);
        String tokenHex = new BigInteger(tokenJson.getBytes()).toString(16);
        return tokenHex;
    }

    private XxlJobUser parseToken(String tokenHex) {
        XxlJobUser xxlJobUser = null;
        if (tokenHex != null) {
            String tokenJson = new String(new BigInteger(tokenHex, 16).toByteArray());      // username_password(md5)
            xxlJobUser = JacksonUtil.readValue(tokenJson, XxlJobUser.class);
        }
        return xxlJobUser;
    }


    // ---------------------- login tool, with cookie and db ----------------------

    public ReturnT<String> login(HttpServletRequest request, HttpServletResponse response, String username, String password, boolean ifRemember) {

        // param
        if (username == null || username.trim().length() == 0 || password == null || password.trim().length() == 0) {
            return new ReturnT<String>(500, I18nUtil.getString("login_param_empty"));
        }

        // valid passowrd
        XxlJobUser xxlJobUser = xxlJobUserDao.loadByUserName(username);
        if (xxlJobUser == null) {
            return new ReturnT<String>(500, I18nUtil.getString("login_param_unvalid"));
        }
        String passwordMd5 = DigestUtils.md5DigestAsHex(password.getBytes());
        if (!passwordMd5.equals(xxlJobUser.getPassword())) {
            return new ReturnT<String>(500, I18nUtil.getString("login_param_unvalid"));
        }

        String loginToken = makeToken(xxlJobUser);

        // do login
        CookieUtil.set(response, LOGIN_IDENTITY_KEY, loginToken, ifRemember);
        return ReturnT.SUCCESS;
    }

    /**
     * logout
     *
     * @param request
     * @param response
     */
    public ReturnT<String> logout(HttpServletRequest request, HttpServletResponse response) {
        CookieUtil.remove(request, response, LOGIN_IDENTITY_KEY);
        return ReturnT.SUCCESS;
    }

    /**
     * logout
     *
     * @param request
     * @return
     */
    public XxlJobUser ifLogin(HttpServletRequest request, HttpServletResponse response) {
        String cookieToken = CookieUtil.getValue(request, LOGIN_IDENTITY_KEY);
        if (checkToken(request)) {
            return tokenLogin(request, response);
        } else if (cookieToken != null) {
            XxlJobUser cookieUser = null;
            try {
                cookieUser = parseToken(cookieToken);
            } catch (Exception e) {
                logout(request, response);
            }
            if (cookieUser != null) {
                XxlJobUser dbUser = xxlJobUserDao.loadByUserName(cookieUser.getUsername());
                if (dbUser != null) {
                    if (cookieUser.getPassword().equals(dbUser.getPassword())) {
                        return dbUser;
                    }
                }
            }
        }
        return null;
    }

    private Boolean checkToken(HttpServletRequest request) {
        String token = request.getParameter("token");
        return StrUtil.isNotEmpty(token);
    }

    private XxlJobUser tokenLogin(HttpServletRequest request, HttpServletResponse response) {
        String token = request.getParameter("token");
        log.info("认证token={}", token);
        // 创建生成器实例
        log.info("xxl.job.accessToken={}", this.xxlJobAdminConfig.getAccessToken());
        JwtAccessTokenGenerator generator = new JwtAccessTokenGenerator(this.xxlJobAdminConfig.getAccessToken());
        Map<String, Object> data = generator.parseToken(token);
        log.info("认证token-data={}", data);
        if (Objects.isNull(data) || !data.containsKey("sub") || StrUtil.isEmpty((String) data.get("sub"))) {
            return null;
        }
        String username = (String) data.get("sub");
        log.info("认证username={}", username);
        XxlJobUser dbUser = xxlJobUserDao.loadByUserName(username);
        if (dbUser != null) {
            String loginToken = makeToken(dbUser);
            // do login
            CookieUtil.set(response, LOGIN_IDENTITY_KEY, loginToken, Boolean.TRUE);
            return dbUser;
        }
        return null;
    }


}
